
package com.ww.springboot.boot.config;

import cn.hutool.core.collection.CollectionUtil;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;

import java.time.Duration;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

public class RedisUtils {
    private final RedisTemplate<String, Object> redisTemplate;

    private String replaceKey(String key) {
        return key;
    }


    public void set(String key, Object value) {
        this.getValueOps().set(this.replaceKey(key), value);
    }

    public void setEx(String key, Object value, Duration timeout) {
        this.getValueOps().set(this.replaceKey(key), value, timeout);
    }

    public void setEx(String key, Object value, Long seconds) {
        this.getValueOps().set(this.replaceKey(key), value, Duration.ofSeconds(seconds));
    }

    public <T> T get(String key) {
        return (T) this.getValueOps().get(this.replaceKey(key));
    }

    public <T> T get(String key, Supplier<T> loader) {
        T value = (T) this.getValueOps().get(this.replaceKey(key));
        if (value != null) {
            return value;
        } else {
            value = loader.get();
            if (value == null) {
                return null;
            } else {
                this.getValueOps().set(this.replaceKey(key), value);
                return value;
            }
        }
    }


    public Boolean del(String key) {
        return this.getRedisTemplate().delete(this.replaceKey(key));
    }

    public Long del(String... keys) {
        List<String> list = new ArrayList();
        String[] var3 = keys;
        int var4 = keys.length;

        for (int var5 = 0; var5 < var4; ++var5) {
            String key = var3[var5];
            list.add(this.replaceKey(key));
        }

        return this.getRedisTemplate().delete(list);
    }

    public Long del(Collection<String> keys) {
        keys.forEach(this::replaceKey);
        return this.getRedisTemplate().delete(keys);
    }

    public Set<String> keys(String pattern) {
        return this.getRedisTemplate().keys(pattern);
    }


    public List<Object> mGet(String... keys) {
        List<String> list = new ArrayList();
        String[] var3 = keys;
        int var4 = keys.length;

        for (int var5 = 0; var5 < var4; ++var5) {
            String key = var3[var5];
            list.add(this.replaceKey(key));
        }

        return this.getValueOps().multiGet(list);
    }

    public List<Object> mGet(Collection<String> keys) {
        Iterator var2 = keys.iterator();

        while (var2.hasNext()) {
            String key = (String) var2.next();
            this.replaceKey(key);
        }

        return this.getValueOps().multiGet(keys);
    }

    public Long decr(String key) {
        return this.getValueOps().decrement(this.replaceKey(key));
    }

    public Long decrBy(String key, long longValue) {
        return this.getValueOps().decrement(this.replaceKey(key), longValue);
    }

    public Long incr(String key) {
        return this.getValueOps().increment(this.replaceKey(key));
    }

    public Long incrBy(String key, long longValue) {
        return this.getValueOps().increment(this.replaceKey(key), longValue);
    }

    public Long getCounter(String key) {
        return Long.valueOf(String.valueOf(this.getValueOps().get(this.replaceKey(key))));
    }

    public Boolean exists(String key) {
        return this.getRedisTemplate().hasKey(this.replaceKey(key));
    }

    public String randomKey() {
        return (String) this.getRedisTemplate().randomKey();
    }

    public void rename(String oldkey, String newkey) {
        this.getRedisTemplate().rename(this.replaceKey(oldkey), this.replaceKey(newkey));
    }

    public Boolean move(String key, int dbIndex) {
        return this.getRedisTemplate().move(this.replaceKey(key), dbIndex);
    }

    public Boolean expire(String key, long seconds) {
        return this.getRedisTemplate().expire(this.replaceKey(key), seconds, TimeUnit.SECONDS);
    }

    public Boolean expire(String key, Duration timeout) {
        return this.getRedisTemplate().expire(this.replaceKey(key), timeout);
    }

    public Boolean expireAt(String key, Date date) {
        return this.getRedisTemplate().expireAt(this.replaceKey(key), date);
    }

    public Boolean expireAt(String key, long unixTime) {
        return this.getRedisTemplate().expireAt(this.replaceKey(key), new Date(unixTime));
    }

    public Boolean pexpire(String key, long milliseconds) {
        return this.getRedisTemplate().expire(this.replaceKey(key), milliseconds, TimeUnit.MILLISECONDS);
    }

    public <T> T getSet(String key, Object value) {
        return (T) this.getValueOps().getAndSet(this.replaceKey(key), value);
    }

    public Boolean persist(String key) {
        return this.getRedisTemplate().persist(this.replaceKey(key));
    }

    public String type(String key) {
        return this.getRedisTemplate().type(this.replaceKey(key)).code();
    }

    public Long ttl(String key) {
        return this.getRedisTemplate().getExpire(this.replaceKey(key));
    }

    public Long pttl(String key) {
        return this.getRedisTemplate().getExpire(this.replaceKey(key), TimeUnit.MILLISECONDS);
    }

    public void hSet(String key, Object field, Object value) {
        this.getHashOps().put(this.replaceKey(key), field, value);
    }

    public void hMset(String key, Map<Object, Object> hash) {
        this.getHashOps().putAll(this.replaceKey(key), hash);
    }

    public <T> T hGet(String key, Object field) {
        return (T) this.getHashOps().get(this.replaceKey(key), field);
    }

    public List hmGet(String key, Object... fields) {
        return this.getHashOps().multiGet(this.replaceKey(key), Arrays.asList(fields));
    }

    public List hmGet(String key, Collection<Object> hashKeys) {
        return this.getHashOps().multiGet(this.replaceKey(key), hashKeys);
    }

    public Long hDel(String key, Object... fields) {
        return this.getHashOps().delete(this.replaceKey(key), fields);
    }

    public Boolean hExists(String key, Object field) {
        return this.getHashOps().hasKey(this.replaceKey(key), field);
    }

    public Map hGetAll(String key) {
        return this.getHashOps().entries(this.replaceKey(key));
    }

    public List hVals(String key) {
        return this.getHashOps().values(this.replaceKey(key));
    }

    public Set<Object> hKeys(String key) {
        return this.getHashOps().keys(this.replaceKey(key));
    }

    public Long hLen(String key) {
        return this.getHashOps().size(this.replaceKey(key));
    }

    public Long hIncrBy(String key, Object field, long value) {
        return this.getHashOps().increment(this.replaceKey(key), field, value);
    }

    public Double hIncrByFloat(String key, Object field, double value) {
        return this.getHashOps().increment(this.replaceKey(key), field, value);
    }

    public <T> T lIndex(String key, long index) {
        return (T) this.getListOps().index(this.replaceKey(key), index);
    }

    public Long lLen(String key) {
        return this.getListOps().size(this.replaceKey(key));
    }

    public <T> T lPop(String key) {
        return (T) this.getListOps().leftPop(this.replaceKey(key));
    }

    public Long lPush(String key, Object... values) {
        return this.getListOps().leftPushAll(this.replaceKey(key), values);
    }

    public void lSet(String key, long index, Object value) {
        this.getListOps().set(this.replaceKey(key), index, value);
    }

    public Long lRem(String key, long count, Object value) {
        return this.getListOps().remove(this.replaceKey(key), count, value);
    }

    public List lRange(String key, long start, long end) {
        return this.getListOps().range(this.replaceKey(key), start, end);
    }

    public void lTrim(String key, long start, long end) {
        this.getListOps().trim(this.replaceKey(key), start, end);
    }

    public <T> T rPop(String key) {
        return (T) this.getListOps().rightPop(this.replaceKey(key));
    }

    public Long rPush(String key, Object... values) {
        return this.getListOps().rightPush(this.replaceKey(key), values);
    }

    public <T> T rPopLPush(String srcKey, String dstKey) {
        return (T) this.getListOps().rightPopAndLeftPush(this.replaceKey(srcKey), this.replaceKey(dstKey));
    }

    public Long sAdd(String key, Object... members) {
        return this.getSetOps().add(this.replaceKey(key), members);
    }

    public <T> T sPop(String key) {
        return (T) this.getSetOps().pop(this.replaceKey(key));
    }

    public Set sMembers(String key) {
        return this.getSetOps().members(this.replaceKey(key));
    }

    public boolean sIsMember(String key, Object member) {
        return this.getSetOps().isMember(this.replaceKey(key), member);
    }

    public Set sInter(String key, String otherKey) {
        return this.getSetOps().intersect(this.replaceKey(key), this.replaceKey(otherKey));
    }

    public Set sInter(String key, Collection<String> otherKeys) {
        otherKeys.forEach(this::replaceKey);
        return this.getSetOps().intersect(this.replaceKey(key), otherKeys);
    }

    public <T> T sRandMember(String key) {
        return (T) this.getSetOps().randomMember(this.replaceKey(key));
    }

    public List sRandMember(String key, int count) {
        return this.getSetOps().randomMembers(this.replaceKey(key), (long) count);
    }

    public Long sRem(String key, Object... members) {
        return this.getSetOps().remove(this.replaceKey(key), members);
    }

    public Set sUnion(String key, String otherKey) {
        return this.getSetOps().union(this.replaceKey(key), this.replaceKey(otherKey));
    }

    public Set sUnion(String key, Collection<String> otherKeys) {
        otherKeys.forEach(this::replaceKey);
        return this.getSetOps().union(this.replaceKey(key), otherKeys);
    }

    public Set sDiff(String key, String otherKey) {
        return this.getSetOps().difference(this.replaceKey(key), this.replaceKey(otherKey));
    }

    public Set sDiff(String key, Collection<String> otherKeys) {
        otherKeys.forEach(this::replaceKey);
        return this.getSetOps().difference(this.replaceKey(key), otherKeys);
    }

    public Boolean zAdd(String key, Object member, double score) {
        return this.getZSetOps().add(this.replaceKey(key), member, score);
    }

    public Long zAdd(String key, Map<Object, Double> scoreMembers) {
        Set<TypedTuple<Object>> tuples = new HashSet();
        scoreMembers.forEach((k, v) -> {
            tuples.add(new DefaultTypedTuple(k, v));
        });
        return this.getZSetOps().add(this.replaceKey(key), tuples);
    }

    public Long zCard(String key) {
        return this.getZSetOps().zCard(this.replaceKey(key));
    }

    public Long zCount(String key, double min, double max) {
        return this.getZSetOps().count(this.replaceKey(key), min, max);
    }

    public Double zIncrBy(String key, Object member, double score) {
        return this.getZSetOps().incrementScore(this.replaceKey(key), member, score);
    }

    public Set zRange(String key, long start, long end) {
        return this.getZSetOps().range(this.replaceKey(key), start, end);
    }

    public Set zRevrange(String key, long start, long end) {
        return this.getZSetOps().reverseRange(this.replaceKey(key), start, end);
    }

    public Set zRangeByScore(String key, double min, double max) {
        return this.getZSetOps().rangeByScore(this.replaceKey(key), min, max);
    }

    public Long zRank(String key, Object member) {
        return this.getZSetOps().rank(this.replaceKey(key), member);
    }

    public Long zRevrank(String key, Object member) {
        return this.getZSetOps().reverseRank(this.replaceKey(key), member);
    }

    public Long zRem(String key, Object... members) {
        return this.getZSetOps().remove(this.replaceKey(key), members);
    }

    public Double zScore(String key, Object member) {
        return this.getZSetOps().score(this.replaceKey(key), member);
    }

    public RedisTemplate<String, Object> getRedisTemplate() {
        return this.redisTemplate;
    }

    public ValueOperations<String, Object> getValueOps() {
        return this.getRedisTemplate().opsForValue();
    }

    public HashOperations<String, Object, Object> getHashOps() {
        return this.getRedisTemplate().opsForHash();
    }

    public ListOperations<String, Object> getListOps() {
        return this.getRedisTemplate().opsForList();
    }

    public SetOperations<String, Object> getSetOps() {
        return this.getRedisTemplate().opsForSet();
    }

    public ZSetOperations<String, Object> getZSetOps() {
        return this.getRedisTemplate().opsForZSet();
    }

    public RedisUtils(final RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }
}
